package com.kxmall.framework.monitor;

import cn.dev33.satoken.stp.StpUtil;
import com.kxmall.common.enums.DeviceType;
import com.kxmall.common.enums.UserType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Token隔离监控器
 * 监控用户和骑手Token的隔离情况，防止串号
 *
 * @author kxmall
 */
@Slf4j
@Component
public class TokenIsolationMonitor {

    // 监控统计
    private final AtomicLong appTokenCount = new AtomicLong(0);
    private final AtomicLong riderTokenCount = new AtomicLong(0);
    private final AtomicLong isolationViolationCount = new AtomicLong(0);
    private final AtomicLong tokenConflictCount = new AtomicLong(0);

    // Token映射表（用于检测冲突）
    private final ConcurrentHashMap<String, TokenInfo> activeTokens = new ConcurrentHashMap<>();

    /**
     * Token信息
     */
    public static class TokenInfo {
        public String tokenValue;
        public String loginId;
        public String userType;
        public String deviceType;
        public Long userId;
        public String openId;
        public long createTime;

        public TokenInfo(String tokenValue, String loginId, String userType, String deviceType, Long userId, String openId) {
            this.tokenValue = tokenValue;
            this.loginId = loginId;
            this.userType = userType;
            this.deviceType = deviceType;
            this.userId = userId;
            this.openId = openId;
            this.createTime = System.currentTimeMillis();
        }
    }

    /**
     * 记录Token创建
     */
    public void recordTokenCreation(String openId, UserType userType, DeviceType deviceType, Long userId) {
        try {
            String tokenValue = StpUtil.getTokenValue();
            String loginId = StpUtil.getLoginIdAsString();
            String device = StpUtil.getLoginDevice();

            // 创建Token信息
            TokenInfo tokenInfo = new TokenInfo(tokenValue, loginId, userType.getUserType(), device, userId, openId);

            // 检查是否存在冲突
            checkTokenConflict(openId, tokenInfo);

            // 记录到活跃Token表
            String key = generateTokenKey(openId, userType, deviceType);
            activeTokens.put(key, tokenInfo);

            // 更新统计
            if (DeviceType.APP.equals(deviceType)) {
                appTokenCount.incrementAndGet();
            } else if (DeviceType.RIDER.equals(deviceType)) {
                riderTokenCount.incrementAndGet();
            }

            log.info("✅ Token创建记录 - OpenId: {}, 用户类型: {}, 设备: {}, 用户ID: {}, Token前缀: {}",
                maskOpenId(openId), userType.getUserType(), device, userId,
                tokenValue != null ? tokenValue.substring(0, Math.min(10, tokenValue.length())) + "..." : "null");

        } catch (Exception e) {
            log.error("记录Token创建异常", e);
        }
    }

    /**
     * 检查Token冲突
     */
    private void checkTokenConflict(String openId, TokenInfo newToken) {
        try {
            // 检查同一openId是否有其他活跃Token
            for (TokenInfo existingToken : activeTokens.values()) {
                if (openId.equals(existingToken.openId)) {
                    // 同一openId，检查是否为不同设备类型
                    if (!newToken.deviceType.equals(existingToken.deviceType)) {
                        log.info("🔄 检测到同一用户多设备登录 - OpenId: {}, 现有设备: {}, 新设备: {}",
                            maskOpenId(openId), existingToken.deviceType, newToken.deviceType);
                    } else if (!newToken.userType.equals(existingToken.userType)) {
                        // 同一设备类型但不同用户类型 - 这是异常情况
                        tokenConflictCount.incrementAndGet();
                        log.warn("🚨 检测到Token冲突 - OpenId: {}, 现有用户类型: {}, 新用户类型: {}",
                            maskOpenId(openId), existingToken.userType, newToken.userType);
                    }
                }
            }
        } catch (Exception e) {
            log.error("检查Token冲突异常", e);
        }
    }

    /**
     * 验证Token隔离
     */
    public void validateTokenIsolation(String openId, UserType expectedUserType, DeviceType expectedDeviceType) {
        try {
            String actualLoginId = StpUtil.getLoginIdAsString();
            String actualDevice = StpUtil.getLoginDevice();

            // 验证用户类型隔离
            if (!actualLoginId.startsWith(expectedUserType.getUserType() + ":")) {
                isolationViolationCount.incrementAndGet();
                log.error("🚨 Token用户类型隔离违规 - OpenId: {}, 期望: {}, 实际LoginId: {}",
                    maskOpenId(openId), expectedUserType.getUserType(), actualLoginId);
                throw new RuntimeException("Token用户类型隔离违规");
            }

            // 验证设备类型隔离
            if (!expectedDeviceType.getDevice().equals(actualDevice)) {
                isolationViolationCount.incrementAndGet();
                log.error("🚨 Token设备类型隔离违规 - OpenId: {}, 期望: {}, 实际: {}",
                    maskOpenId(openId), expectedDeviceType.getDevice(), actualDevice);
                throw new RuntimeException("Token设备类型隔离违规");
            }

            log.debug("✅ Token隔离验证通过 - OpenId: {}, 用户类型: {}, 设备: {}",
                maskOpenId(openId), expectedUserType.getUserType(), expectedDeviceType.getDevice());

        } catch (Exception e) {
            log.error("Token隔离验证异常", e);
            throw e;
        }
    }

    /**
     * 清理过期Token记录
     */
    public void cleanupExpiredTokens() {
        try {
            long currentTime = System.currentTimeMillis();
            long expireTime = 24 * 60 * 60 * 1000; // 24小时

            activeTokens.entrySet().removeIf(entry -> {
                TokenInfo tokenInfo = entry.getValue();
                return (currentTime - tokenInfo.createTime) > expireTime;
            });

            log.debug("Token记录清理完成，当前活跃Token数量: {}", activeTokens.size());
        } catch (Exception e) {
            log.error("清理过期Token记录异常", e);
        }
    }

    /**
     * 获取监控统计
     */
    public String getMonitoringStats() {
        return String.format(
            "Token隔离监控统计 - APP Token: %d, 骑手Token: %d, 隔离违规: %d, Token冲突: %d, 活跃Token: %d",
            appTokenCount.get(), riderTokenCount.get(), isolationViolationCount.get(),
            tokenConflictCount.get(), activeTokens.size()
        );
    }

    /**
     * 重置统计
     */
    public void resetStats() {
        appTokenCount.set(0);
        riderTokenCount.set(0);
        isolationViolationCount.set(0);
        tokenConflictCount.set(0);
        activeTokens.clear();
        log.info("Token隔离监控统计已重置");
    }

    /**
     * 生成Token键
     */
    private String generateTokenKey(String openId, UserType userType, DeviceType deviceType) {
        return openId + ":" + userType.getUserType() + ":" + deviceType.getDevice();
    }

    /**
     * 掩码OpenId
     */
    private String maskOpenId(String openId) {
        if (openId == null || openId.length() <= 10) {
            return openId;
        }
        return openId.substring(0, 10) + "...";
    }

    /**
     * 检查是否存在隔离违规
     */
    public boolean hasIsolationViolations() {
        return isolationViolationCount.get() > 0 || tokenConflictCount.get() > 0;
    }
}
